using RSCore;

namespace _ReplaceString_.UI.Animations;
public abstract record UIMove : UIAnimation
{
	public static UIMove Move(Vector2 start, Vector2 end, float speed = 64) => new Move(start, end, speed);
	public static UIMove FlyIn(Vector2 end, Direction direction, float speed = 64) => new FlyIn(end, direction, speed);
	public static UIMove FlyOut(Direction direction, float speed = 64) => new FlyOut(direction, speed);
}

file record Move(Vector2 Start, Vector2 End, float Speed) : UIMove
{
	/// <summary>
	/// Left与Top的精确值，用于进行浮点修正
	/// </summary>
	public Vector2 Target;

	public override void Begin(UIBase ui)
	{
		var move = Start - ui.Position;
		Target = End - ui.Position;
		Target.X += ui.Left.Pixels;
		Target.Y += ui.Top.Pixels;
		ui.Left.Pixels += move.X;
		ui.Top.Pixels += move.Y;
		ui.Recalculate();
	}

	public override IEnumerable<int> Update(UIBase ui)
	{
		Vector2 move;
		do
		{
			yield return 0;
			move = ui.Position.Approach(End, Speed) - ui.Position;
			ui.Left.Pixels += move.X;
			ui.Top.Pixels += move.Y;
			ui.Recalculate();
		} while (move != Vector2.Zero);
		ui.Left.Pixels = Target.X;
		ui.Top.Pixels = Target.Y;
	}
}

file record FlyIn(Vector2 End, Direction MoveDirection, float Speed) : UIMove
{
	/// <summary>
	/// Left与Top的精确值，用于进行浮点修正
	/// </summary>
	public Vector2 Target;
	public override void Begin(UIBase ui)
	{
		const int MagicNumber = 4;
		var start = MoveDirection switch
		{
			Direction.Left => new Vector2(Main.screenWidth + MagicNumber, End.Y),
			Direction.Right => new Vector2(-ui.Size.X - MagicNumber, End.Y),
			Direction.Up => new Vector2(End.X, Main.screenHeight + MagicNumber),
			Direction.Down => new Vector2(End.X, -ui.Size.Y - MagicNumber),
			_ => throw new NotImplementedException("?"),
		};
		var move = start - ui.Position;
		Target = End - ui.Position;
		Target.X += ui.Left.Pixels;
		Target.Y += ui.Top.Pixels;
		ui.Left.Pixels += move.X;
		ui.Top.Pixels += move.Y;
	}

	public override IEnumerable<int> Update(UIBase ui)
	{
		Vector2 move;
		do
		{
			yield return 0;
			move = ui.Position.Approach(End, Speed) - ui.Position;
			ui.Left.Pixels += move.X;
			ui.Top.Pixels += move.Y;
			ui.Recalculate();
		} while (move != Vector2.Zero);
		ui.Left.Pixels = Target.X;
		ui.Top.Pixels = Target.Y;
	}
}

file record FlyOut(Direction MoveDirection, float Speed) : UIMove
{
	public Vector2 Target;
	public override void Begin(UIBase ui)
	{
		const int MagicNumber = 4;
		var position = ui.Position;
		Target = MoveDirection switch
		{
			Direction.Left => new Vector2(-ui.Size.X - MagicNumber, position.Y),
			Direction.Right => new Vector2(Main.screenWidth + MagicNumber, position.Y),
			Direction.Up => new Vector2(position.X, Main.screenHeight + MagicNumber),
			Direction.Down => new Vector2(position.X, -ui.Size.Y - MagicNumber),
			_ => throw new NotImplementedException("?"),
		};
	}

	public override IEnumerable<int> Update(UIBase ui)
	{
		Vector2 move;
		do
		{
			yield return 0;
			move = ui.Position.Approach(Target, Speed) - ui.Position;
			ui.Left.Pixels += move.X;
			ui.Top.Pixels += move.Y;
			ui.Recalculate();
		} while (move != Vector2.Zero);
		ui.Deactivate();
	}
}